#include <gtest/gtest.h>
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <chrono>  // ✅ 计时
#include "LinkedListBigInt.h"
#include "StringBigInt.h"
#include "ArrayBigInt.h"
#include "BoostBigInt.h"

using namespace std;
using namespace chrono;  // ✅ 简化 chrono 代码

// 生成随机大整数
std::string generateLargeNumber(int length) {
    std::string num;
    num += '1' + rand() % 9;
    for (int i = 1; i < length; i++) {
        num += '0' + rand() % 10;
    }
    return num;
}

// 将字符串转换为链表
ListNode* stringToLinkedList(const string& num) {
    ListNode* dummy = new ListNode(0);
    ListNode* curr = dummy;
    for (int i = num.size() - 1; i >= 0; i--) {
        curr->next = new ListNode(num[i] - '0');
        curr = curr->next;
    }
    return dummy->next;
}

// 将字符串转换为数组
vector<int> stringToArray(const string& num) {
    vector<int> arr;
    for (char c : num) arr.push_back(c - '0');
    return arr;
}

// **计时工具函数**
template<typename Func>
double benchmark(Func func, int iterations = 1000) {
    auto start = high_resolution_clock::now();
    for (int i = 0; i < iterations; i++) {
        func();
    }
    auto end = high_resolution_clock::now();
    return duration<double, milli>(end - start).count() / iterations;  // 平均时间 (ms)
}

// **存储测试结果到 CSV**
void saveResultsToCSV(const vector<int>& digits, const vector<double>& linkedListTimes,
                      const vector<double>& stringTimes, const vector<double>& arrayTimes,
                      const vector<double>& boostTimes) {
    ofstream file("performance_results.csv");
    file << "Digits,LinkedList,String,Array,Boost\n";
    for (size_t i = 0; i < digits.size(); i++) {
        file << digits[i] << "," << linkedListTimes[i] << "," << stringTimes[i] << "," 
             << arrayTimes[i] << "," << boostTimes[i] << "\n";
    }
    file.close();
}


// **测试 LinkedListBigInt**
TEST(BigIntegerTest, LinkedListAddition) {
    std::string num1 = "999";
    std::string num2 = "1";
    ListNode* l1 = stringToLinkedList(num1);
    ListNode* l2 = stringToLinkedList(num2);
    ListNode* result = LinkedListBigInt::addTwoNumbers(l1, l2);

    std::string expected = "1000";
    ListNode* temp = result;
    std::string actual;
    while (temp) {
        actual = std::to_string(temp->val) + actual;
        temp = temp->next;
    }

    EXPECT_EQ(actual, expected);
}

// **测试 StringBigInt**
TEST(BigIntegerTest, StringAddition) {
    std::string num1 = "456";
    std::string num2 = "77";
    std::string result = StringBigInt::addStrings(num1, num2);
    EXPECT_EQ(result, "533");
}

// **测试 ArrayBigInt**
TEST(BigIntegerTest, ArrayAddition) {
    std::vector<int> num1 = {9, 9, 9};
    std::vector<int> num2 = {1};
    std::vector<int> result = ArrayBigInt::addArrays(num1, num2);
    std::vector<int> expected = {0, 0, 0, 1};
    EXPECT_EQ(result, expected);
}


// **测试大整数加法的性能**
TEST(BigIntegerPerformanceTest, MeasureExecutionTime) {
    using namespace boost::multiprecision;
    vector<int> bit_sizes = {100, 200, 500, 1000, 2000, 5000, 10000};
    vector<double> linkedListTimes, stringTimes, arrayTimes, boostTimes;

    for (int digits : bit_sizes) {
        cout << "Testing " << digits << "-digit numbers..." << endl;

        string num1 = generateLargeNumber(digits);
        string num2 = generateLargeNumber(digits);

        // **测试链表**
        ListNode* l1 = stringToLinkedList(num1);
        ListNode* l2 = stringToLinkedList(num2);
        double linkedListTime = benchmark([&]() {
            ListNode* res = LinkedListBigInt::addTwoNumbers(l1, l2);
            delete res;
        });
        linkedListTimes.push_back(linkedListTime);

        // **测试字符串**
        double stringTime = benchmark([&]() {
            StringBigInt::addStrings(num1, num2);
        });
        stringTimes.push_back(stringTime);

        // **测试数组**
        vector<int> arr1 = stringToArray(num1);
        vector<int> arr2 = stringToArray(num2);
        double arrayTime = benchmark([&]() {
            ArrayBigInt::addArrays(arr1, arr2);
        });
        arrayTimes.push_back(arrayTime);

        // **提前解析输入**
        cpp_int boostNum1(num1);
        cpp_int boostNum2(num2);
        // **测试 Boost**
        double boostTime = benchmark([&]() {
            BoostBigInt::addBigNumbers(boostNum1, boostNum2);
        });
        boostTimes.push_back(boostTime);

        // **打印结果**
        cout << "LinkedList: " << linkedListTime << " ms\n";
        cout << "String: " << stringTime << " ms\n";
        cout << "Array: " << arrayTime << " ms\n";
        cout << "Boost: " << boostTime << " ms\n";
        cout << "--------------------------\n";
    }

    // **保存结果到 CSV**
    saveResultsToCSV(bit_sizes, linkedListTimes, stringTimes, arrayTimes, boostTimes);
    cout << "Performance results saved to performance_results.csv!\n";
}

// **测试 BoostBigInt 性能**
TEST(BoostBigIntPerformanceTest, MeasureExecutionTime) {
    using namespace boost::multiprecision;
    vector<int> bit_sizes = {50, 100, 500, 1000, 5000, 10000};  // 测试不同位数的大整数
    vector<double> parseTimes, addTimes, strTimes;

    cout << "Running BoostBigInt Performance Test...\n";

    for (int digits : bit_sizes) {
        cout << "Testing " << digits << "-digit numbers..." << endl;

        // **生成随机大整数**
        string num1 = generateLargeNumber(digits);
        string num2 = generateLargeNumber(digits);

        // **测试解析字符串到大整数的时间**
        double parseTime = benchmark([&]() {
            cpp_int a(num1);
            cpp_int b(num2);
        });

        // **测试加法操作的时间**
        cpp_int a(num1), b(num2);
        double addTime = benchmark([&]() {
            cpp_int sum = a + b;
        });

        // **测试转换回字符串的时间**
        cpp_int sum = a + b;
        double strTime = benchmark([&]() {
            std::string result = sum.str();
        });

        // **记录结果**
        parseTimes.push_back(parseTime);
        addTimes.push_back(addTime);
        strTimes.push_back(strTime);

        // **输出到终端**
        cout << "Parsing: " << parseTime << " ms\n";
        cout << "Addition: " << addTime << " ms\n";
        cout << "String conversion: " << strTime << " ms\n";
        cout << "--------------------------\n";
    }

    // **保存结果到 CSV**
    ofstream file("boost_bigint_performance.csv");
    file << "Digits,Parsing (ms),Addition (ms),String Conversion (ms)\n";
    for (size_t i = 0; i < bit_sizes.size(); i++) {
        file << bit_sizes[i] << "," << parseTimes[i] << "," << addTimes[i] << "," << strTimes[i] << "\n";
    }
    file.close();

    cout << "BoostBigInt performance results saved to boost_bigint_performance.csv!\n";
}

// **测试入口**
int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
